using System;
using CodePlex.DnD4eCampaignManager.DnD4e.Interfaces;

namespace CodePlex.DnD4eCampaignManager.DnD4e
{
    public class HitPoints : IHitPoints, IEquatable<HitPoints>
    {
        private int _currentHitPoints;
        private int? _hitPointsMaximum;

        public int HitPointsBloodied
        {
            get { return HitPointsMaximum / 2; }
        }

        public int HitPointsCurrent
        {
            get { return _currentHitPoints; }
            set { _currentHitPoints = _hitPointsMaximum.HasValue ? Math.Min(value, HitPointsMaximum) : value; }
        }

        public int HitPointsMaximum
        {
            get { return _hitPointsMaximum.GetValueOrDefault(0); }
            set { _hitPointsMaximum = value; }
        }

        public int HitPointsTemporary { get; set; }

        public bool IsBloodied
        {
            get { return HitPointsCurrent <= HitPointsBloodied; }
        }

        public override bool Equals(object obj)
        {
            if ( ReferenceEquals(null, obj) )
            {
                return false;
            }
            if ( ReferenceEquals(this, obj) )
            {
                return true;
            }
            if ( obj.GetType() != typeof ( HitPoints ) )
            {
                return false;
            }
            return Equals((HitPoints) obj);
        }

        public override int GetHashCode()
        {
            unchecked
            {
                int result = _currentHitPoints;
                result = ( result * 397 ) ^ ( _hitPointsMaximum.HasValue ? _hitPointsMaximum.Value : 0 );
                result = ( result * 397 ) ^ HitPointsTemporary;
                return result;
            }
        }

        public void Damage(int hitPointsLost)
        {
            if ( HitPointsTemporary >= hitPointsLost )
            {
                HitPointsTemporary -= hitPointsLost;
            }
            else
            {
                hitPointsLost -= HitPointsTemporary;
                HitPointsTemporary = 0;
                HitPointsCurrent -= hitPointsLost;
            }
        }

        public bool Equals(HitPoints other)
        {
            if ( ReferenceEquals(null, other) )
            {
                return false;
            }
            if ( ReferenceEquals(this, other) )
            {
                return true;
            }
            return other._currentHitPoints == _currentHitPoints && other._hitPointsMaximum.Equals(_hitPointsMaximum) &&
                   other.HitPointsTemporary == HitPointsTemporary;
        }

        public void Heal(int hitPointsRecovered)
        {
            HitPointsCurrent += hitPointsRecovered;
        }

        public static bool operator ==(HitPoints left, HitPoints right)
        {
            return Equals(left, right);
        }

        public static bool operator !=(HitPoints left, HitPoints right)
        {
            return !Equals(left, right);
        }
    }
}